﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
using Toolkit.Web.ExtensionMethods;
using System.ComponentModel;

namespace Toolkit.Web.ViewComponents.DataGrid
{
    public interface IDataGridColumnFilterInputModel
    {
        string Key
        {
            get;
            set;
        }

        DataGridFilterOperator Operator
        {
            get;
            set;
        }

        IDataExpressionInputModel FieldExpression
        {
            get;
            set;
        }

        string FieldValueType
        {
            get;
            set;
        }

        IList<string> FieldValues
        {
            get;
            set;
        }

        void CleanModel();
    }

    public interface IPersistentDataGridColumnFilterModel
    {
        string Key
        {
            get;
            set;
        }

        DataGridFilterOperator Operator
        {
            get;
            set;
        }

        IPersistentDataExpressionModel FieldExpression
        {
            get;
            set;
        }

        string FieldValueType
        {
            get;
            set;
        }

        IList<string> FieldValues
        {
            get;
            set;
        }

        void CleanModel();
    }

    [DataContract]
    public class DataGridColumnFilterInputModel : IDataGridColumnFilterInputModel, IPersistentDataGridColumnFilterModel
    {
        public DataGridColumnFilterInputModel()
        {
            Key = Guid.NewGuid().ToString();
        }

        [DataMember]
        public string Key
        {
            get;
            set;
        }

        [DataMember]
        public DataGridFilterOperator Operator
        {
            get;
            set;
        }

        [DataMember]
        public DataExpressionInputModel FieldExpression
        {
            get;
            set;
        }

        IDataExpressionInputModel IDataGridColumnFilterInputModel.FieldExpression
        {
            get
            {
                if (FieldExpression != null)
                {
                    return ((IDataExpressionInputModel)FieldExpression);
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    FieldExpression = ((DataExpressionInputModel)value);
                }
                else
                {
                    FieldExpression = null;
                };
            }
        }

        IPersistentDataExpressionModel IPersistentDataGridColumnFilterModel.FieldExpression
        {
            get
            {
                if (FieldExpression != null)
                {
                    return ((IPersistentDataExpressionModel)FieldExpression);
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    FieldExpression = ((DataExpressionInputModel)value);
                }
                else
                {
                    FieldExpression = null;
                };
            }
        }

        [DataMember]
        public string FieldValueType
        {
            get;
            set;
        }

        [DataMember]
        public IList<string> FieldValues
        {
            get;
            set;
        }

        public void CleanModel()
        {
            Type type = Type.GetType(FieldValueType, true, true);

            CleanFieldValueType(type);
            CleanFieldValues(type);
            CleanOperator(type);
        }

        private void CleanFieldValueType(Type type)
        {
            if (type.GetInterface(typeof(IComparable).FullName) == null)
            {
                throw new Exception("Invalid field value type. Type must implement IComparable.");
            }

            if ((Operator == DataGridFilterOperator.StartsWith || Operator == DataGridFilterOperator.EndsWith) && type != typeof(string))
            {
                throw new Exception("Field value type does not support operator.");
            }
        }

        private void CleanFieldValues(Type type)
        {
            if (FieldValues == null || FieldValues.Count == 0)
            {
                FieldValues = new List<string>();
                return;
            }

            IList<string> values = FieldValues;
            IList<string> verifiedValues = new List<string>();

            foreach (string value in values)
            {
                string verifiedValue = CleanFieldValue(value, type);

                if (string.IsNullOrEmpty(verifiedValue))
                {
                    verifiedValues.Add(string.Empty);
                }
                else
                {
                    verifiedValues.Add(verifiedValue);
                }
            }

            if (verifiedValues.FirstOrDefault(v => !string.IsNullOrEmpty(v)) == null)
            {
                verifiedValues.Clear();
            }

            FieldValues = verifiedValues;
        }

        private string CleanFieldValue(string value, Type type)
        {
            object obj = null;

            try
            {
                // Even though this will be of type Object, it's underlying type matches the type passed in and therefor
                // the ToString() method will call the underlying implementation and yeild the desired string.
                obj = value.Convert(type);

                if (obj != null)
                {
                    return obj.ToString();
                }
            }
            catch
            {
            }

            return null;
        }

        private void CleanOperator(Type type)
        {
            if (FieldValues == null)
            {
                FieldValues = new List<string>();
            }

            if (Operator == DataGridFilterOperator.None)
            {
                FieldValues.Clear();
                return;
            }
            else if (Operator == DataGridFilterOperator.IsEmptyOrNull || Operator == DataGridFilterOperator.IsNotEmptyOrNull)
            {
                FieldValues.Clear();
                return;
            }

            if (FieldValues.FirstOrDefault(v => !string.IsNullOrEmpty(v)) == null)
            {
                Operator = DataGridFilterOperator.None;
                FieldValues.Clear();
                return;
            }

            if (Operator == DataGridFilterOperator.IsLessThan || Operator == DataGridFilterOperator.IsLessThanOrEqualTo)
            {
                if (string.IsNullOrEmpty(FieldValues[0]))
                {
                    Operator = DataGridFilterOperator.None;
                    FieldValues.Clear();
                }
                else
                {
                    FieldValues = FieldValues.Take(1).ToList();
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.IsEqualTo)
            {
                if (string.IsNullOrEmpty(FieldValues[0]))
                {
                    Operator = DataGridFilterOperator.IsEmptyOrNull;
                    FieldValues.Clear();
                }
                else
                {
                    FieldValues = FieldValues.Take(1).ToList();
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.IsNotEqualTo)
            {
                if (string.IsNullOrEmpty(FieldValues[0]))
                {
                    Operator = DataGridFilterOperator.IsNotEmptyOrNull;
                    FieldValues.Clear();
                }
                else
                {
                    FieldValues = FieldValues.Take(1).ToList();
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.IsGreaterThan || Operator == DataGridFilterOperator.IsGreaterThanOrEqualTo)
            {
                if (string.IsNullOrEmpty(FieldValues[0]))
                {
                    Operator = DataGridFilterOperator.None;
                    FieldValues.Clear();
                }
                else
                {
                    FieldValues = FieldValues.Take(1).ToList();
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.StartsWith || Operator == DataGridFilterOperator.EndsWith)
            {
                if (string.IsNullOrEmpty(FieldValues[0]))
                {
                    Operator = DataGridFilterOperator.None;
                    FieldValues.Clear();
                }
                else
                {
                    FieldValues = FieldValues.Take(1).ToList();
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.Contains || Operator == DataGridFilterOperator.DoesNotContain)
            {
                FieldValues = FieldValues.Where(v => !string.IsNullOrEmpty(v)).ToList();
                if (FieldValues.Count == 0)
                {
                    Operator = DataGridFilterOperator.None;
                }
                return;
            }
            else if (Operator == DataGridFilterOperator.IsContainedIn || Operator == DataGridFilterOperator.IsNotContainedIn)
            {
                FieldValues = FieldValues.Where(v => !string.IsNullOrEmpty(v)).ToList();
                if (FieldValues.Count == 0)
                {
                    Operator = DataGridFilterOperator.None;
                }
                return;
            }
        }
    }
}
